package core

import (
	"strconv"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
)

type Selector struct {
	Type string // Text / Attr
	Attr string // Attr获取指定属性
	Dom  string // DOM元素
}

type Pagination struct {
	Enable       bool
	HostJoint    bool
	Selector     Selector
	PagesAllByEq int
	CorrectNum   int
}

type Prey struct {
	Enable    bool
	Selectors []Selector
}

type PreySource struct {
	BoxSelector    Selector
	TitleSelector  Selector
	SourceSelector Selector
}

type Source struct {
	Title string
	Url   string
	Pages []string
	Srcs  []string
}

// 页面分析
func UrlAnalysis(url string, prey Prey) (results []string, err error) {
	// 获取页面
	doc, err := goquery.NewDocument(url)
	if err != nil {
		return nil, err
	}
	if prey.Enable {
		// 遍历选择器
		for _, selector := range prey.Selectors {
			doc.Find(selector.Dom).Each(func(i int, s *goquery.Selection) {
				var result string

				// 内容搜集
				switch selector.Type {
				case "Text":
					result = strings.TrimSpace(s.Text())
				case "Attr":
					if attr, ok := s.Attr(selector.Attr); ok {
						result = strings.TrimSpace(attr)
					}
				}

				// 内容归纳
				if result != "" {
					results = append(results, result)
				}
			})
		}
	}
	return
}

// 分页分析
func PaginationUrlAnalysis(url string, pagination Pagination) (pages []string, err error) {
	// 获取页面
	doc, err := goquery.NewDocument(url)
	if err != nil {
		return nil, err
	}
	// 保留当前页URL
	pages = append(pages, doc.Url.String())
	if pagination.Enable {
		// 总页数
		EqIndex := pagination.PagesAllByEq
		pagesAll, err := strconv.Atoi(doc.Find(pagination.Selector.Dom).Eq(EqIndex).Text())
		pagesLastReplace := strconv.Itoa(pagesAll - pagination.CorrectNum)
		if err != nil {
			pagesAll = 0
		}
		if pagesAll > 0 {
			// 获取分页URL模板
			var urlTpl string
			switch pagination.Selector.Type {
			case "Text":
				urlTpl = strings.TrimSpace(doc.Find(pagination.Selector.Dom).Eq(EqIndex).Text())
			case "Attr":
				if attr, ok := doc.Find(pagination.Selector.Dom).Eq(EqIndex).Attr(pagination.Selector.Attr); ok {
					urlTpl = strings.TrimSpace(attr)
				}
			}
			createUrls := func(pagesAll int, urlTpl, tplType string) {
				host := ""
				if pagination.HostJoint {
					host = doc.Url.Scheme + "://" + doc.Url.Host
				}
				for i := 1; i <= pagesAll; i++ {
					pages = append(pages, host+strings.Replace(urlTpl, tplType, strings.Replace(tplType, pagesLastReplace, strconv.Itoa(i), -1), -1))
				}
			}
			// 分页集合
			if strings.Index(urlTpl, "/"+pagesLastReplace) > -1 {
				createUrls(pagesAll, urlTpl, "/"+pagesLastReplace)
				return pages, nil
			}
			if strings.Index(urlTpl, "-"+pagesLastReplace) > -1 {
				createUrls(pagesAll, urlTpl, "-"+pagesLastReplace)
				return pages, nil
			}
			if strings.Index(urlTpl, "_"+pagesLastReplace) > -1 {
				createUrls(pagesAll, urlTpl, "_"+pagesLastReplace)
				return pages, nil
			}
			if strings.Index(urlTpl, pagesLastReplace+".") > -1 {
				createUrls(pagesAll, urlTpl, pagesLastReplace+".")
				return pages, nil
			}
		}
	}
	return
}

// 猎物源分析
func PreySourceAnalysis(url string, preySources []PreySource) (sources []Source, err error) {
	// 获取页面
	doc, err := goquery.NewDocument(url)
	if err != nil {
		return nil, err
	}
	for _, preySource := range preySources {
		// BOX
		doc.Find(preySource.BoxSelector.Dom).Each(func(i int, s *goquery.Selection) {
			var title string
			var url string
			var source Source
			// 标题获取
			doc.Find(preySource.TitleSelector.Dom).Eq(i).Each(func(i int, s *goquery.Selection) {
				switch preySource.TitleSelector.Type {
				case "Text":
					title = strings.TrimSpace(s.Text())
				case "Attr":
					if attr, ok := s.Attr(preySource.TitleSelector.Attr); ok {
						title = strings.TrimSpace(attr)
					}
				}
			})
			// 源获取
			doc.Find(preySource.SourceSelector.Dom).Eq(i).Each(func(i int, s *goquery.Selection) {
				switch preySource.SourceSelector.Type {
				case "Text":
					url = strings.TrimSpace(s.Text())
				case "Attr":
					if attr, ok := s.Attr(preySource.SourceSelector.Attr); ok {
						url = strings.TrimSpace(attr)
					}
				}
			})
			if title == "" {
				title = strconv.Itoa(int(time.Now().UnixNano()))
			}
			if url != "" {
				source.Title = title
				source.Url = url
				sources = append(sources, source)
			}
		})
	}
	return sources, nil
}
